﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// NotReviewedButNeeded
#pragma once

#include "Vector2i.h"
#include "Vector2d.h"
#include "Vector3d.h"
#include "Vector4d.h"
#include "Matrix4d.h"
#include "Matrix3d.h"
#include "Intervald.h"
#include "Box2d.h"
#include "Box3d.h"
#include "TiltBox3d.h"
#include "Color.h"
#include "Coordinate3d.h"
#include "GbmpGuid.h"
#include "RuntimeId.h"
#include "OwnerPtr.h"
#include "NdbPropertySchemaType.h"
#include "NdbObjectSchematic.h"
#include "NdbObjectCloneable.h"
#include "NdbObjectContainer.h"
#include "IDbObject.h"

namespace gcmp
{
    class ElementId;

    template <typename T, typename Enable = void>
    struct property_is_value_type : std::false_type {};

    // 值类型。包括Ndb自定义的基础类型以及C++内建值类型，这些类型可以用内存拷贝的方式复制。
    template <typename T>
    struct property_is_value_type<T, typename std::enable_if<
        std::is_same<T, UInt8>::value || std::is_same<T, UInt16>::value || std::is_same<T, UInt32>::value || std::is_same<T, UInt64>::value ||
        std::is_same<T, Int8>::value || std::is_same<T, Int16>::value || std::is_same<T, Int32>::value || std::is_same<T, Int64>::value ||
        std::is_same<T, float>::value || std::is_same<T, double>::value ||
        std::is_enum<T>::value || std::is_same<T, Byte>::value || std::is_same<T, Bool>::value || std::is_same<T, WChar>::value ||
        std::is_same<T, Guid>::value    ||
        std::is_same<T, RuntimeId>::value  ||
        std::is_same<T, Color>::value  ||
        std::is_same<T, Vector2d>::value || std::is_same<T, Vector2i>::value || std::is_same<T, Vector3d>::value || std::is_same<T, Vector4d>::value || 
        std::is_same<T, Matrix3d>::value || std::is_same<T, Matrix4d>::value ||
        std::is_same<T, Intervald>::value ||
        std::is_same<T, Coordinate3d>::value || 
        std::is_same<T, Box2d>::value || std::is_same<T, Box3d>::value || std::is_same<T, TiltBox3d>::value
    >::type> : std::true_type {};

    template <typename T>
    struct property_is_value_type<T, typename std::enable_if<T::clone_as_value::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct is_gcmp_type : std::false_type {};

    template <typename T>
    struct is_gcmp_type<T, typename std::enable_if<
        std::is_same<T, UInt8>::value || std::is_same<T, UInt16>::value || std::is_same<T, UInt32>::value || std::is_same<T, UInt64>::value ||
        std::is_same<T, Int8>::value || std::is_same<T, Int16>::value || std::is_same<T, Int32>::value || std::is_same<T, Int64>::value ||
        std::is_same<T, float>::value || std::is_same<T, double>::value ||
        std::is_enum<T>::value || std::is_same<T, Byte>::value || std::is_same<T, Bool>::value || std::is_same<T, WChar>::value ||
        std::is_same<T, Guid>::value ||
        std::is_same<T, RuntimeId>::value ||
        std::is_same<T, Color>::value ||
        std::is_same<T, Vector2d>::value || std::is_same<T, Vector2i>::value || std::is_same<T, Vector3d>::value || std::is_same<T, Vector4d>::value ||
        std::is_same<T, Matrix3d>::value || std::is_same<T, Matrix4d>::value ||
        std::is_same<T, Intervald>::value ||
        std::is_same<T, Coordinate3d>::value ||
        std::is_same<T, Box2d>::value || std::is_same<T, Box3d>::value || std::is_same<T, TiltBox3d>::value
    >::type> : std::true_type{};

    template <typename T>
    struct property_is_elementId_type : std::false_type {};

    template <>
    struct property_is_elementId_type<ElementId> : std::true_type {};

    template <typename T>
    struct property_is_wstring_type : std::false_type {};

    template <>
    struct property_is_wstring_type<std::wstring> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_object_cloneable_type : std::false_type {};

    template <typename T>
    struct property_is_object_cloneable_type<T, typename std::enable_if<std::is_base_of<gcmp::NdbObjectCloneable, T>::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_vector_type : std::false_type {};

    template <typename T>
    struct property_is_vector_type<T, typename std::enable_if<std::is_base_of<gcmp::NdbObjectContainer, T>::value && T::is_vector::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_map_type : std::false_type {};

    template <typename T>
    struct property_is_map_type<T, typename std::enable_if<std::is_base_of<gcmp::NdbObjectContainer, T>::value && T::is_map::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_set_type : std::false_type {};

    template <typename T>
    struct property_is_set_type<T, typename std::enable_if<std::is_base_of<gcmp::NdbObjectContainer, T>::value && T::is_set::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_unordermap_type : std::false_type {};

    template <typename T>
    struct property_is_unordermap_type<T, typename std::enable_if<std::is_base_of<gcmp::NdbObjectContainer, T>::value && T::is_unordermap::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_object_schematic_type : std::false_type {};

    template <typename T>
    struct property_is_object_schematic_type<T, typename std::enable_if<std::is_base_of<gcmp::NdbObjectSchematic, T>::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_object_cloneable_owner_ptr_type : std::false_type {};

    template <typename T>
    struct property_is_object_cloneable_owner_ptr_type<gcmp::OwnerPtr<T>, typename std::enable_if<std::is_base_of<gcmp::NdbObjectCloneable, T>::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_object_schematic_owner_ptr_type : std::false_type {};

    template <typename T>
    struct property_is_object_schematic_owner_ptr_type<gcmp::OwnerPtr<T>, typename std::enable_if<std::is_base_of<gcmp::NdbObjectSchematic, T>::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_idbobject_owner_ptr_type : std::false_type {};

    template <typename T>
    struct property_is_idbobject_owner_ptr_type<gcmp::OwnerPtr<T>, typename std::enable_if<std::is_base_of<gcmp::IDbObject, T>::value>::type> : std::true_type {};

    template <typename T, typename Enable = void>
    struct property_is_idbobject_type : std::false_type {};

    template <typename T>
    struct property_is_idbobject_type<T, typename std::enable_if<std::is_base_of<gcmp::IDbObject, T>::value>::type> : std::true_type {};

    template <typename T>
    struct property_is_owner_ptr_type : std::false_type {};

    template <typename T>
    struct property_is_owner_ptr_type<gcmp::OwnerPtr<T>> : std::true_type {};

    template <typename T, class Enable = void>
    struct NdbPropertySchemaTypeTrait
    {
    public:
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Invalid;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_elementId_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::ElementId;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int64;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_wstring_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::WString;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<float>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Float;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<double>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Double;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<uint8_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UInt8;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<uint16_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UInt16;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<uint32_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UInt32;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<uint64_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UInt64;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<int8_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int8;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<int16_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int16;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<int32_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int32;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<int64_t>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int64;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<Bool>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UInt8;
    };

    template <>
    struct NdbPropertySchemaTypeTrait<Guid>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Hex;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<std::is_enum<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int32;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<!std::is_enum<T>::value && property_is_value_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Value;
        static const IntBaseType IntBaseType = IntBaseType::Dec;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::Int32;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_vector_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Vector;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_set_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Set;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_map_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::Map;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_unordermap_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::UnorderedMap;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_object_cloneable_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::CloneableObject;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<property_is_object_schematic_type<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::SchematicObject;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<T, typename std::enable_if<std::is_pointer<T>::value>::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::NativePointer;
        static const IntBaseType IntBaseType = IntBaseType::Hex;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UInt64;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<gcmp::OwnerPtr<T>, typename std::enable_if<
        property_is_object_cloneable_owner_ptr_type<gcmp::OwnerPtr<T>>::value ||
        property_is_object_schematic_owner_ptr_type<gcmp::OwnerPtr<T>>::value
    >::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::OwnerPtrToNdbObject;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template <typename T>
    struct NdbPropertySchemaTypeTrait<gcmp::OwnerPtr<T>, typename std::enable_if<
        !property_is_object_cloneable_owner_ptr_type<gcmp::OwnerPtr<T>>::value &&
        !property_is_object_schematic_owner_ptr_type<gcmp::OwnerPtr<T>>::value &&
        property_is_idbobject_owner_ptr_type<gcmp::OwnerPtr<T>>::value
    >::type>
    {
        static const NdbPropertySchemaType PropertySchemaType = NdbPropertySchemaType::OwnerPtrToIDbObject;
        static const IntBaseType IntBaseType = IntBaseType::UnKnown;
        static const IntOrFloatType IntOrFloatType = IntOrFloatType::UnKnown;
    };

    template<bool uisbase, bool isownerptr, typename U, typename T>
    struct Convert_Type_If
    {
        static const int templatetype = 1;
        static U* GetData(T* data)
        {
            //FYI(L"Convert_Type_If: T* data")
            return nullptr;
        }
        static U* GetData(T& data)
        {
            //FYI(L"Convert_Type_If: T& data")
            return nullptr;
        }
        static U* GetData(const T& data)
        {
            //FYI(L"Convert_Type_If: const T& data")
            return nullptr;
        }
        static U* GetData(const T* data)
        {
            //FYI(L"Convert_Type_If: const T* data")
            return nullptr;
        }
        static U* GetData(OwnerPtr<T>& data)
        {
            //FYI(L"Convert_Type_If: OwnerPtr<T>& data")
            return nullptr;
        }
        //static U* GetData(IDbObject* data) { return nullptr; }
    };

    template< typename U, typename T>
    struct Convert_Type_If<true, false, U, T>
    {
        static const int templatetype = 2;
        static U* GetData(T* data)
        {
            //FYI(L"Convert_Type_If: true T* data")
            return data;
        }
        static U* GetData(T& data)
        {
            //FYI(L"Convert_Type_If: true T& data")
            return &data;
        }
        static const U* GetData(const T& data)
        {
            //FYI(L"Convert_Type_If: true const T& data")
            return &data;
        }
        static const U* GetData(const T* data)
        {
            //FYI(L"Convert_Type_If: true const T* data")
            return data;
        }
        static U* GetData(OwnerPtr<T>& data)
        {
            //FYI(L"Convert_Type_If: true OwnerPtr<T>& data")
            return data.get();
        }
    };

    template<typename I>
    struct GetInnerType
    {
        static I* Get(I* data)
        {
            return data;
        }
        static I* Get(I& data)
        {
            return &data;
        }
    };

    template<typename I>
    struct GetInnerType<OwnerPtr<I>>
    {
        static I* Get(OwnerPtr<I>& data)
        {
            return data.get();
        }

        static const I* Get(const OwnerPtr<I>& data)
        {
            return data.get();
        }
    };

    template< typename U, typename T>
    struct Convert_Type_If<false, true, U, OwnerPtr<T>>
    {
        static const int templatetype = 3;

        static const U* GetData(const OwnerPtr<T>& data)
        {
            //FYI(L"Convert_Type_If: false isownerptr OwnerPtr<T>& data");
            //auto res =const_cast<T*>( data.get());

            const U* pObject = dynamic_cast<const U*>(data.get());//Convert_Type_If<std::is_base_of<U, T>::value, property_is_owner_ptr_type<T>::value, U, T>::GetData(res);
            return pObject;
        }
        static const U* GetData(const T* data)
        {
            //FYI(L"Convert_Type_If: false isownerptr const T* data");
            return data;
        }
        static U* GetData(OwnerPtr<T>& data)
        {
            //FYI(L"Convert_Type_If: false isownerptr OwnerPtr<T>& data");
            auto res = data.get();
            U* pObject = dynamic_cast<U*>(res);
            //U* pObject = Convert_Type_If<std::is_base_of<U, T>::value, property_is_owner_ptr_type<T>::value, U, T>::GetData(res);
            return pObject;
        }
    };

    template<typename T>
    struct GetNonConstPoint
    {
        static T* GetNonConstPointImp(const T* pObject)
        {
            return nullptr;
        }
        static T* GetNonConstPointImp(T* pObject)
        {
            return nullptr;
        }

        static T* GetNonConstPointImp(T pObject)
        {
            return nullptr;
        }
    };

    template<>
    struct GetNonConstPoint<NdbObject>
    {
        static NdbObject* GetNonConstPointImp(const NdbObject* pObject)
        {
            return const_cast<NdbObject*>(pObject);
        }
        static NdbObject* GetNonConstPointImp(NdbObject* pObject)
        {
            return pObject;
        }

    };


    template<>
    struct GetNonConstPoint<NdbObject*>
    {
        static NdbObject* GetNonConstPointImp(const NdbObject* pObject)
        {
            return const_cast<NdbObject*>(pObject);
        }
        static NdbObject* GetNonConstPointImp(NdbObject* pObject)
        {
            return pObject;
        }

    };

    template<>
    struct GetNonConstPoint<IDbObject>
    {
        static IDbObject* GetNonConstPointImp(const IDbObject* pObject)
        {
            return const_cast<IDbObject*>(pObject);
        }
        static IDbObject* GetNonConstPointImp(IDbObject* pObject)
        {
            return pObject;
        }

    };

    template<>
    struct GetNonConstPoint<IDbObject*>
    {
        static IDbObject* GetNonConstPointImp(const IDbObject* pObject)
        {
            return const_cast<IDbObject*>(pObject);
        }
        static IDbObject* GetNonConstPointImp(IDbObject* pObject)
        {
            return pObject;
        }

    };

}
